﻿using System;
using QQ2564874169.Core.Caching;
using QQ2564874169.Json;
using QQ2564874169.RelationalSql;

namespace QQ2564874169.Cache.Db
{
    public class DbCache : ICache
    {
        private IDbExecute _execute;
        private IDbEntityQuery _query;

        public DbCache(IDbExecute execute, IDbEntityQuery query)
        {
            _execute = execute;
            _query = query;
        }

        private static bool IsValid(DbCacheItem item)
        {
            if (item == null)
            {
                return false;
            }
            if (item.AbsoluteExpiration.HasValue)
            {
                if (item.CreateTime.GetValueOrDefault().AddSeconds(item.AbsoluteExpiration.Value) < DateTime.Now)
                    return false;
            }
            if (item.SlidingExpiration.HasValue)
            {
                if (item.GetTime.GetValueOrDefault().AddSeconds(item.SlidingExpiration.Value) < DateTime.Now)
                    return false;
            }
            return true;
        }

        public void Save(CacheItem data)
        {
            if (data.Value == null)
                throw new ArgumentException("data.value is null.");
            if (data.Key == null)
                throw new ArgumentException("data.key is null.");

            var model = _query.Get(new DbCacheItem { Key = data.Key });
            if (model == null)
            {
                _execute.Insert(new DbCacheItem
                {
                    Id = Guid.NewGuid().ToString().Replace("-", "").ToLower(),
                    AbsoluteExpiration = data.AbsoluteExpiration,
                    SlidingExpiration = data.SlidingExpiration,
                    CreateTime = DateTime.Now,
                    GetTime = DateTime.Now,
                    Key = data.Key,
                    Value = JsonHelper.ToJson(data.Value),
                    ValueType = data.Value.GetType().AssemblyQualifiedName
                });
            }
            else
            {
                _execute.Update(new DbCacheItem
                {
                    AbsoluteExpiration = data.AbsoluteExpiration,
                    SlidingExpiration = data.SlidingExpiration,
                    CreateTime = DateTime.Now,
                    GetTime = DateTime.Now,
                    Value = JsonHelper.ToJson(data.Value),
                    ValueType = data.Value.GetType().AssemblyQualifiedName,
                    Id = model.Id
                });
            }

        }

        public void Update(string key, object value)
        {
            var item = _query.Get(new DbCacheItem {Key = key});
            if (IsValid(item))
            {
                var newitem = new DbCacheItem
                {
                    Value = JsonHelper.ToJson(value),
                    ValueType = value.GetType().AssemblyQualifiedName,
                    Id = item.Id
                };
                if (item.SlidingExpiration.HasValue)
                {
                    newitem.GetTime = DateTime.Now;
                }
                _execute.Update(newitem);
                return;
            }
            if (item != null)
            {
                _execute.Delete(new DbCacheItem {Id = item.Id});
            }
            throw new DbCacheException("缓存项不存在：" + key);
        }

        public bool Exists(string key)
        {
            var item = _query.Get(new DbCacheItem { Key = key });
            return IsValid(item);
        }

        public object Get(string key)
        {
            var item = _query.Get(new DbCacheItem {Key = key});
            if (IsValid(item) == false)
            {
                if (item != null)
                {
                    _execute.Delete(new DbCacheItem {Id = item.Id});
                }
                return null;
            }

            if (item.SlidingExpiration.HasValue)
            {
                _execute.Update(new DbCacheItem {Id = item.Id, GetTime = DateTime.Now});
            }

            var t = Type.GetType(item.ValueType, false);
            if (t == null)
            {
                throw new DbCacheException($"无法加载类型：{item.ValueType}");
            }
            return JsonHelper.JsonTo(item.Value, t);
        }

        public void Remove(string key)
        {
            _execute.Delete(new DbCacheItem {Key = key});
        }
    }
}
